/* Complet (Autocompletion through Graph Databases)
 *  Copyright (C) 2012  Paul Wagner, Till Speicher
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 3 of the License, or (at your
 *  option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, see <http:/* www.gnu.org/licenses/>.
 */

/*
 * Tool to norm a complet database
 *
 * @author Paul Wagner
 *
 */
package complet.app.io.dbnormer;

import complet.db.DBConn;
import complet.helper.ConfigHelper;
import complet.helper.IOHelper;
import java.util.HashMap;
import java.util.Set;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;

public class DBNormer {

    private static final Boolean DOLOC = true;
    private static final Boolean DOSUM = false;
    private static HashMap<String, HashMap<Long, Relationship>> nodeMap1 = new HashMap<String, HashMap<Long, Relationship>>();
    private static HashMap<String, HashMap<Long, Relationship>> nodeMap2 = new HashMap<String, HashMap<Long, Relationship>>();
    private static HashMap<String, HashMap<Long, Relationship>> nodeMap3 = new HashMap<String, HashMap<Long, Relationship>>();
    private static HashMap<String, HashMap<Long, Relationship>> nodeMap4 = new HashMap<String, HashMap<Long, Relationship>>();

    public static void main(String[] args) {
        // Load Config file
        ConfigHelper.DB_PATH = "E:\\paul\\Dokumente\\MyDocuments\\NetBeans Workspace\\Completion\\dbs\\db_5grams.db";
        ConfigHelper.BUFFER = false;
        if (args.length > 0) {
            ConfigHelper.loadConfigFile(args[0]);
        }

        IOHelper.pln("Starting Operations with " + ConfigHelper.DB_PATH);
        // Establish DB connection
        DBConn conn = new DBConn();
        conn.openTransaction();

        // Globale und lokale Maxima bestimmen und normieren
        double max_loc = 0;
        double max_sum = 0;
        double cur = 0;
        int cnt = 0;

        if (DOSUM) {
            IOHelper.pln("Doing Sum Norming...");

            cnt = 0;
            IOHelper.pln("Buffer node relationships");
            // Buffer node rels
            String name = "";
            HashMap<Long, Relationship> tmp = null;
            for (Node n : conn.getGraph().getAllNodes()) {
                cnt++;
                if (!n.hasProperty(ConfigHelper.NAME_KEY)) {
                    continue;
                }
                name = (String) n.getProperty(ConfigHelper.NAME_KEY);
                tmp = new HashMap<Long, Relationship>();
                for (Relationship r : n.getRelationships(conn.getDn()[1], Direction.OUTGOING)) {
                    tmp.put(r.getId(), r);
                }
                nodeMap1.put(name, tmp);
                tmp = new HashMap<Long, Relationship>();
                for (Relationship r : n.getRelationships(conn.getDn()[2], Direction.OUTGOING)) {
                    tmp.put(r.getId(), r);
                }
                nodeMap2.put(name, tmp);
                tmp = new HashMap<Long, Relationship>();
                for (Relationship r : n.getRelationships(conn.getDn()[3], Direction.OUTGOING)) {
                    tmp.put(r.getId(), r);
                }
                nodeMap3.put(name, tmp);
                tmp = new HashMap<Long, Relationship>();
                for (Relationship r : n.getRelationships(conn.getDn()[4], Direction.OUTGOING)) {
                    tmp.put(r.getId(), r);
                }
                nodeMap4.put(name, tmp);
                IOHelper.pln(cnt + ": Next node...");
            }
            IOHelper.pln("Finished buffer node relationships");


            // Now iterate nodes and relationship to obtain sum norm
            cnt = 0;
            Set<String> set;
            Set<Long> set2;
            Relationship r = null;
            HashMap<Long, Relationship> rel = new HashMap<Long, Relationship>();

            // rel:1
            set = nodeMap1.keySet();
            for (String key : set) {
                rel = nodeMap1.get(key);
                set2 = rel.keySet();
                max_loc = 0;
                max_sum = 0;
                IOHelper.pln("rel:1 " + (cnt + 1) + ": Get node sum and maximum");
                for (Long key2 : set2) {
                    // Get sum
                    cur = (Integer) rel.get(key2).getProperty(ConfigHelper.COUNT_KEY);
                    max_sum += cur;
                    // Get loc maximum
                    if (cur > max_loc) {
                        max_loc = cur;
                    }
                }
                IOHelper.pln("rel:1 " + (cnt + 1) + ": Write node rels");
                for (Long key2 : set2) {
                    cnt++;
                    // Write sum
                    r = rel.get(key2);
                    cur = (Integer) r.getProperty(ConfigHelper.COUNT_KEY);
                    r.setProperty(ConfigHelper.RELSUM_KEY, cur / max_sum);
                    r.setProperty(ConfigHelper.RELLOC_KEY, cur / max_loc);
                    if (cnt % 50000 == 49999) {
                        conn.commitTransaction();
                        IOHelper.pln("Commiting...");
                    }
                }
            }

            // rel:2
            set = nodeMap2.keySet();
            for (String key : set) {
                rel = nodeMap2.get(key);
                set2 = rel.keySet();
                max_loc = 0;
                max_sum = 0;
                IOHelper.pln("rel:2 " + (cnt + 1) + ": Get node sum");
                for (Long key2 : set2) {
                    // Get sum
                    cur = (Integer) rel.get(key2).getProperty(ConfigHelper.COUNT_KEY);
                    max_sum += cur;
                    // Get loc maximum
                    if (cur > max_loc) {
                        max_loc = cur;
                    }
                }
                IOHelper.pln("rel:2 " + (cnt + 1) + ": Write node rels");
                for (Long key2 : set2) {
                    cnt++;
                    // Write loc maximum
                    r = rel.get(key2);
                    cur = (Integer) r.getProperty(ConfigHelper.COUNT_KEY);
                    r.setProperty(ConfigHelper.RELSUM_KEY, cur / max_sum);
                    r.setProperty(ConfigHelper.RELLOC_KEY, cur / max_loc);
                    if (cnt % 50000 == 49999) {
                        conn.commitTransaction();
                        IOHelper.pln("Commiting...");
                    }
                }
            }

            // rel:3
            set = nodeMap3.keySet();
            for (String key : set) {
                rel = nodeMap3.get(key);
                set2 = rel.keySet();
                max_loc = 0;
                max_sum = 0;
                IOHelper.pln("rel:3 " + (cnt + 1) + ": Get node sum");
                for (Long key2 : set2) {
                    // Get sum
                    cur = (Integer) rel.get(key2).getProperty(ConfigHelper.COUNT_KEY);
                    max_sum += cur;
                    // Get loc maximum
                    if (cur > max_loc) {
                        max_loc = cur;
                    }
                }
                IOHelper.pln("rel:3 " + (cnt + 1) + ": Write node rels");
                for (Long key2 : set2) {
                    cnt++;
                    // Write loc maximum
                    r = rel.get(key2);
                    cur = (Integer) r.getProperty(ConfigHelper.COUNT_KEY);
                    r.setProperty(ConfigHelper.RELSUM_KEY, cur / max_sum);
                    r.setProperty(ConfigHelper.RELLOC_KEY, cur / max_loc);
                    if (cnt % 50000 == 49999) {
                        conn.commitTransaction();
                        IOHelper.pln("Commiting...");
                    }
                }
            }

            // rel:4
            set = nodeMap4.keySet();
            for (String key : set) {
                rel = nodeMap4.get(key);
                set2 = rel.keySet();
                max_loc = 0;
                max_sum = 0;
                IOHelper.pln("rel:4 " + (cnt + 1) + ": Get node sum");
                for (Long key2 : set2) {
                    // Get sum
                    cur = (Integer) rel.get(key2).getProperty(ConfigHelper.COUNT_KEY);
                    max_sum += cur;
                    // Get loc maximum
                    if (cur > max_loc) {
                        max_loc = cur;
                    }
                }
                IOHelper.pln("rel:4 " + (cnt + 1) + ": Write node rels");
                for (Long key2 : set2) {
                    cnt++;
                    // Write loc maximum
                    r = rel.get(key2);
                    cur = (Integer) r.getProperty(ConfigHelper.COUNT_KEY);
                    r.setProperty(ConfigHelper.RELSUM_KEY, cur / max_sum);
                    r.setProperty(ConfigHelper.RELLOC_KEY, cur / max_loc);
                    if (cnt % 50000 == 49999) {
                        conn.commitTransaction();
                        IOHelper.pln("Commiting...");
                    }
                }
            }
            conn.commitTransaction();
            IOHelper.pln("Commiting...");

            IOHelper.pln("Finished Sum Norming...");
        }

        if (DOLOC) {
            IOHelper.pln("Doing Loc Norming...");

            cnt = 0;
            IOHelper.pln("Buffer node relationships");
            // Buffer node rels
            String name = "";
            HashMap<Long, Relationship> tmp = null;
            for (Node n : conn.getGraph().getAllNodes()) {
                cnt++;
                if (!n.hasProperty(ConfigHelper.NAME_KEY)) {
                    continue;
                }
                name = (String) n.getProperty(ConfigHelper.NAME_KEY);
                tmp = new HashMap<Long, Relationship>();
                for (Relationship r : n.getRelationships(conn.getDn()[1], Direction.OUTGOING)) {
                    tmp.put(r.getId(), r);
                }
                nodeMap1.put(name, tmp);
                tmp = new HashMap<Long, Relationship>();
                for (Relationship r : n.getRelationships(conn.getDn()[2], Direction.OUTGOING)) {
                    tmp.put(r.getId(), r);
                }
                nodeMap2.put(name, tmp);
                tmp = new HashMap<Long, Relationship>();
                for (Relationship r : n.getRelationships(conn.getDn()[3], Direction.OUTGOING)) {
                    tmp.put(r.getId(), r);
                }
                nodeMap3.put(name, tmp);
                tmp = new HashMap<Long, Relationship>();
                for (Relationship r : n.getRelationships(conn.getDn()[4], Direction.OUTGOING)) {
                    tmp.put(r.getId(), r);
                }
                nodeMap4.put(name, tmp);
                IOHelper.pln(cnt + ": Next node...");
            }
            IOHelper.pln("Finished buffer node relationships");


            // Now iterate nodes and relationship to obtain loc norm
            cnt = 0;
            Set<String> set;
            Set<Long> set2;
            Relationship r = null;
            HashMap<Long, Relationship> rel = new HashMap<Long, Relationship>();

            // rel:1
            set = nodeMap1.keySet();
            for (String key : set) {
                rel = nodeMap1.get(key);
                set2 = rel.keySet();
                max_loc = 0;
                IOHelper.pln("rel:1 " + (cnt + 1) + ": Get node maximum");
                for (Long key2 : set2) {
                    // Get loc maximum
                    cur = (Integer) rel.get(key2).getProperty(ConfigHelper.COUNT_KEY);
                    if (cur > max_loc) {
                        max_loc = cur;
                    }
                }
                IOHelper.pln("rel:1 " + (cnt + 1) + ": Write node rels");
                for (Long key2 : set2) {
                    cnt++;
                    // Write loc maximum
                    r = rel.get(key2);
                    cur = (Integer) r.getProperty(ConfigHelper.COUNT_KEY);
                    r.setProperty(ConfigHelper.RELLOC_KEY, cur / max_loc);
                    if (cnt % 50000 == 49999) {
                        conn.commitTransaction();
                        IOHelper.pln("Commiting...");
                    }
                }
            }

            // rel:2
            set = nodeMap2.keySet();
            for (String key : set) {
                rel = nodeMap2.get(key);
                set2 = rel.keySet();
                max_loc = 0;
                IOHelper.pln("rel:2 " + (cnt + 1) + ": Get node maximum");
                for (Long key2 : set2) {
                    // Get loc maximum
                    cur = (Integer) rel.get(key2).getProperty(ConfigHelper.COUNT_KEY);
                    if (cur > max_loc) {
                        max_loc = cur;
                    }
                }
                IOHelper.pln("rel:2 " + (cnt + 1) + ": Write node rels");
                for (Long key2 : set2) {
                    cnt++;
                    // Write loc maximum
                    r = rel.get(key2);
                    cur = (Integer) r.getProperty(ConfigHelper.COUNT_KEY);
                    r.setProperty(ConfigHelper.RELLOC_KEY, cur / max_loc);
                    if (cnt % 50000 == 49999) {
                        conn.commitTransaction();
                        IOHelper.pln("Commiting...");
                    }
                }
            }

            // rel:3
            set = nodeMap3.keySet();
            for (String key : set) {
                rel = nodeMap3.get(key);
                set2 = rel.keySet();
                max_loc = 0;
                IOHelper.pln("rel:3 " + (cnt + 1) + ": Get node maximum");
                for (Long key2 : set2) {
                    // Get loc maximum
                    cur = (Integer) rel.get(key2).getProperty(ConfigHelper.COUNT_KEY);
                    if (cur > max_loc) {
                        max_loc = cur;
                    }
                }
                IOHelper.pln("rel:3 " + (cnt + 1) + ": Write node rels");
                for (Long key2 : set2) {
                    cnt++;
                    // Write loc maximum
                    r = rel.get(key2);
                    cur = (Integer) r.getProperty(ConfigHelper.COUNT_KEY);
                    r.setProperty(ConfigHelper.RELLOC_KEY, cur / max_loc);
                    if (cnt % 50000 == 49999) {
                        conn.commitTransaction();
                        IOHelper.pln("Commiting...");
                    }
                }
            }

            // rel:4
            set = nodeMap4.keySet();
            for (String key : set) {
                rel = nodeMap4.get(key);
                set2 = rel.keySet();
                max_loc = 0;
                IOHelper.pln("rel:4 " + (cnt + 1) + ": Get node maximum");
                for (Long key2 : set2) {
                    // Get loc maximum
                    cur = (Integer) rel.get(key2).getProperty(ConfigHelper.COUNT_KEY);
                    if (cur > max_loc) {
                        max_loc = cur;
                    }
                }
                IOHelper.pln("rel:4 " + (cnt + 1) + ": Write node rels");
                for (Long key2 : set2) {
                    cnt++;
                    // Write loc maximum
                    r = rel.get(key2);
                    cur = (Integer) r.getProperty(ConfigHelper.COUNT_KEY);
                    r.setProperty(ConfigHelper.RELLOC_KEY, cur / max_loc);
                    if (cnt % 50000 == 49999) {
                        conn.commitTransaction();
                        IOHelper.pln("Commiting...");
                    }
                }
            }
            conn.commitTransaction();
            IOHelper.pln("Commiting...");

            IOHelper.pln("Finished Loc Norming...");

        }

        IOHelper.pln("FINISHED.");

        conn.closeTransaction();
        conn.closeConnection();
    }
}
